package config

/*
   @author:zhongyang
   @date:2023/8/29
   @description:
*/

import (
	"encoding/json"
	"fmt"
	"gitee.com/zylvcxq/gotham-utils/map_util"
	"github.com/go-kratos/kratos/contrib/config/apollo/v2"
	"github.com/go-kratos/kratos/v2/config"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"reflect"
	"strings"
)

func InitConfig(globalConfig interface{}, opts ...apollo.Option) (func(), error) {
	// 阿波罗配置
	source := apollo.NewSource(
		opts...,
	)
	c := config.New(
		config.WithSource(
			source,
		),
	)
	watcher, err := source.Watch()
	if err != nil {
		panic(err)
	}
	if err := c.Load(); err != nil {
		panic(err)
	}

	if err := c.Scan(globalConfig); err != nil {
		panic(err)
	}
	go func() {
		for {
			keyValues, _ := watcher.Next()
			for _, item := range keyValues {
				// 解析成扁平map
				flatMap := dealConfigValue(item)
				// 通过反射动态修改配置值
				// 获取字段的反射值
				//循环找到所有需要更改的值
				for key, value := range flatMap {
					structValue := reflect.ValueOf(globalConfig).Elem()
					fieldValue := structValue
					// 将key进行分割处理
					fields := strings.Split(key, ".")
					// 找到对应的key，然后修改值
					for _, field := range fields {
						// FieldByName方法的调用者只能是结构体，如果是指针需要转换一下
						if fieldValue.Kind() == reflect.Pointer {
							fieldValue = fieldValue.Elem()
						}
						fieldValue = fieldValue.FieldByName(cases.Title(language.English).String(field))
					}
					// 检查字段是否存在
					if fieldValue.IsValid() {
						// 检查字段是否可以被修改
						if fieldValue.CanSet() {
							// 根据字段类型设置新值
							switch fieldValue.Kind() {
							case reflect.Int:
								valueInt64, ok := value.(int64)
								if !ok {
									fmt.Println("int64转换失败")
									continue
								}
								fieldValue.SetInt(valueInt64)
							case reflect.String:
								valueString, ok := value.(string)
								if !ok {
									fmt.Println("string转换失败")
									continue
								}
								fieldValue.SetString(valueString)
							default:
								fmt.Println("Unsupported field type")
							}
							fmt.Println("修改后的结构体:", globalConfig)
						} else {
							fmt.Println("字段不可设置值")
						}
					} else {
						fmt.Println("字段不存在")
					}
				}
			}
		}
	}()
	return func() {
		c.Close()
		watcher.Stop()
	}, err
}

func dealConfigValue(item *config.KeyValue) map[string]interface{} {
	// 解析item.value值
	var data map[string]interface{}
	json.Unmarshal(item.Value, &data)

	// 转换成扁平的结构体，key:字段名.子字段名... || value：基础值，非结构体,int,bool,string...
	flatMap := make(map[string]interface{})
	map_util.Flatten("", ".", data, flatMap)
	return flatMap
}
